package com.mspbots.ticketai.graderule;

import cn.hutool.core.util.NumberUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mspbots.ticketai.GradeRuleInterceptorAdapter;
import com.mspbots.ticketai.model.Ticket;
import com.mspbots.ticketai.model.TicketRule;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;


/**
 * com.mspbots.core.ticketai.NoneGradeRuleInterceptor
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/8/20
 */
@Log4j2
@Service(value = "STATUS_POINTS_GRADE_RULE")
public class StatusPointsGradeRuleInterceptor extends GradeRuleInterceptorAdapter {

    private List<StatusPointsParams> statusPointsParams;

    @Override
    public void prepare(TicketRule rule) {
        this.statusPointsParams = this.objectMapper.convertValue(rule.getParams(), new TypeReference<>() {
        });
    }

    @Override
    public void process(Ticket ticket) {
        long totalMinutes = Duration.between(getStatusTime(ticket), LocalDateTime.now()).toMinutes();
        int order = statusPointsParams.parallelStream()
                .filter(p -> p.getStatus() == ticket.getStatusId())
                .filter(StatusPointsParams::isSelected)
                .map(StatusPointsParams::getPoints)
                .map(statusPoints -> statusPoints.parallelStream().filter(point -> point.getTime() < totalMinutes)
                        .mapToInt(StatusPoints::getPoint).sum()).mapToInt(Integer::intValue).sum();

        ObjectNode objectNode = this.objectMapper.createObjectNode();
        objectNode.put("id", ticket.getStatusId());
        objectNode.put("name", ticket.getStatus());
        String timeSum = NumberUtil.roundStr((float) totalMinutes / 60, 2);
        objectNode.put("detail", timeSum + " hours/" + order);
        objectNode.put("time", timeSum);
        objectNode.put("point", order);

        ObjectNode extendNode = ticket.getOrderDetail() == null ? this.objectMapper.createObjectNode() : ticket.getOrderDetail().deepCopy();
        extendNode.putPOJO("status", objectNode);
        ticket.setOrderDetail(extendNode);
        ticket.setOrder(ticket.getOrder() + order);
    }

    private LocalDateTime getStatusTime(Ticket ticket) {
        if (!ObjectUtils.isEmpty(ticket.getAuditor()) && ticket.getAuditor().size() > 0) {
            List<StatusRecord> statusList = this.objectMapper.convertValue(ticket.getAuditor(), new TypeReference<>() {
            });
            if (!CollectionUtils.isEmpty(statusList)) {
                LocalDateTime time = statusList.get(statusList.size() - 1).getTime();
                return ObjectUtils.isEmpty(time) ? ticket.getUpdatedTime() : time;
            }
        }
        return ticket.getUpdatedTime();
    }

    @Data
    public static class StatusPointsParams {
        private List<StatusPoints> points;
        private int status;
        private boolean selected;
    }

    @Data
    private static class StatusPoints {
        private int time;
        private int point;
    }

    @Data
    private static class StatusRecord {
        private int id;
        private String name;
        private LocalDateTime time;
    }
}
